package com.platform.modules.acme.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.platform.annotation.IgnoreAuth;
import com.platform.common.annotation.ServiceLimit;
import com.platform.common.exception.BusinessException;
import com.platform.common.utils.Constant;
import com.platform.common.utils.RestResponse;
import com.platform.common.utils.VerifyUtils;
import com.platform.config.AcmeProperties;
import com.platform.modules.acme.component.AcmeCache;
import com.platform.modules.acme.component.ChallengeType;
import com.platform.modules.acme.entity.AcmeMemberEntity;
import com.platform.modules.acme.entity.AcmeOrderEntity;
import com.platform.modules.acme.service.AcmeMemberService;
import com.platform.modules.acme.service.AcmeOrderService;
import com.platform.modules.acme.utils.AcmeUtil;
import io.swagger.annotations.ApiOperation;
import lombok.extern.log4j.Log4j;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.shredzone.acme4j.challenge.Dns01Challenge;
import org.shredzone.acme4j.challenge.Http01Challenge;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLDecoder;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

@Slf4j
@RestController
@RequestMapping("/acme")
public class AcmeController {

    @Autowired
    AcmeOrderService letEncryptService;

    @Autowired
    AcmeMemberService acmeMemberService;

    @Autowired
    AcmeCache acmeCache;

    @Autowired
    AcmeProperties acmeProperties;



    /**
     * 下单获取验证信息
     *
     * @param domainNames   域名
     * @param challengeType 验证类型
     * @param email         联系邮箱
     * @param csrData       certificate sign request data
     * @param csrType       csr类型,服务器创建0，前端提供1
     * @param keyType       ECC,RSA
     * @return
     */
    @ServiceLimit
    @IgnoreAuth
    @GetMapping("/getVerifyInfo")
    public RestResponse getVerifyInfo(@RequestParam("domainNames") Set<String> domainNames, @RequestParam("challengeType") String challengeType,
                                      HttpServletRequest request, @RequestParam("keyType") String keyType,
                                      @RequestParam("email") String email, @RequestParam(value = "csrData", required = false) String csrData,
                                      @RequestParam(value = "csrType") Integer csrType) {

        try {
            // make ip cache?
            boolean limitFlag = acmeCache.getLimit(email);
            if (limitFlag) {
                return RestResponse.error("请求太快，请稍后再试!");
            }
        } catch (Exception ex) {
            return RestResponse.error("内部错误，请稍后再试或联系管理员进行处理!");
        }
        //检查域名正确性
        domainNames.stream().forEach(domain->{
            if (!VerifyUtils.isDomain(domain)) {
                throw new BusinessException("域名格式不正确");
            }
        });

        //先判断是否有该用户
        //创建用户再下订单
        QueryWrapper<AcmeMemberEntity> memberQuery = new QueryWrapper<>();
        memberQuery.eq("email", email);
        AcmeMemberEntity memberEntity = acmeMemberService.getOne(memberQuery);
        if (memberEntity == null) {
            memberEntity = new AcmeMemberEntity();
            //此处创建为了以后用户注册可以关联以前下的单
            memberEntity.setAddress("");
            //走注册流程才启动用户
            memberEntity.setAvailable(Constant.ACME_USER_CREATE);
            memberEntity.setCreateTime(LocalDateTime.now());
            memberEntity.setEmail(email);
            memberEntity.setMemberId(UUID.randomUUID().toString());
            acmeMemberService.save(memberEntity);
        }
        if (csrType == 0) {
            //genrate csr
            try {
                csrData = AcmeUtil.getCsrAndPrivateKey(domainNames, acmeProperties.getClientFilePath());
            } catch (IOException e) {
                log.error(e.getMessage());
                throw new RuntimeException("创建CSR失败，请稍后再试!");
            }
        } else {
            //check CSRDATA
            try {
                csrData = URLDecoder.decode(URLDecoder.decode(csrData, "utf-8"),"utf-8");
                log.info(csrData);
//                csrData = URLDecoder.decode(csrData, "utf-8");
                if (!AcmeUtil.chkPkcs10(csrData)) {
                    return RestResponse.error("CSR数据错误，请检查CSR数据!");
                }
            } catch (IOException ex) {
                log.error(ex.getMessage());
                return RestResponse.error("检查CSR数据失败，请稍后再试!");
            }
        }


        Map<String, Object> verifyInfo = null;
        //TODO 通配符只能是DNS验证
        if ("dns".equalsIgnoreCase(challengeType)) {
            verifyInfo = letEncryptService.getVerifyInfo(domainNames, Dns01Challenge.TYPE, memberEntity.getMemberId(), csrData);
        } else if ("http".equalsIgnoreCase(challengeType)) {
            verifyInfo = letEncryptService.getVerifyInfo(domainNames, Http01Challenge.TYPE, memberEntity.getMemberId(), csrData);
        } else {
            return RestResponse.error("请选择正确的验证方式");
        }
        return RestResponse.success(verifyInfo);

    }


    /**
     * Verify the domain info by order id
     *
     * @param orderId
     * @return
     */
    @IgnoreAuth
    @ApiOperation(value="域名验证",notes = "根据订单ID验证")
    @GetMapping("/verifyDomain")
    public RestResponse verifyDomain(@RequestParam("orderId") String orderId) {
        Map<String, Object> retValue = letEncryptService.verifyAuth(orderId);
        return RestResponse.success(retValue);
    }


    @GetMapping("/chkDownload/{orderId}")
    public RestResponse chkDownLoad(@PathVariable("orderId") String orderId) {
        Map<String, Object> retValue = letEncryptService.verifyAuth(orderId);
        if (retValue.get("success").toString().equals("false")) {
            return RestResponse.error().put("success", "false");
        } else {
            return RestResponse.success();
        }
    }


    /**
     * @param orderId
     */
    @GetMapping("/downLoadCerts/{orderId}")
    public void downLoadCert(HttpServletResponse response, @PathVariable String orderId) throws IOException {
        AcmeOrderEntity orderEntity = letEncryptService.getById(orderId);
        String[] domainNames = orderEntity.getDomainName().split(",");
        String domainName = Arrays.stream(domainNames).findFirst().get();
        String fileName = "";
        String wildStart = "*.";
        if (domainName.startsWith(wildStart)) {
            fileName = domainName.replaceFirst("\\*", "_");
        } else {
            fileName = domainName;
        }

        String filePath = acmeProperties.getClientFilePath() + File.separator + fileName + ".zip";
        File file = new File(filePath);
        if (!file.exists()){
            letEncryptService.getCertificate(orderId);
        }
        FileInputStream fis = new FileInputStream(file);
        byte[] certData = new byte[fis.available()];
        fis.read(certData);
        fis.close();
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
        response.setContentType("application/octet-stream;charset=UTF-8");
        OutputStream outputStream = response.getOutputStream();
        IOUtils.write(certData, outputStream);
    }

    /**
     * 下载验证文件
     * @param fileName
     */
    @IgnoreAuth
    @GetMapping("/downloadVerifyFile")
    public void downLoadVerifyFile(HttpServletResponse response,@RequestParam("fileName") String fileName) throws IOException {
        String filePath = acmeProperties.getVerifyFilePath()+File.separator+fileName;
        byte[] bs = FileUtils.readFileToByteArray(new File(filePath));
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
        response.setContentType("application/octet-stream;charset=UTF-8");
        OutputStream outputStream = response.getOutputStream();
        IOUtils.write(bs,outputStream);
    }
}
